package server;

import org.dom4j.*;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * Minicat的主类
 */
public class Bootstrap {

    /**
     * 定义socket监听的端口号
     */
    private int port = 8080;


    private Mapper mapper = new Mapper();

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }


    /**
     * Minicat启动需要初始化展开的一些操作
     */
    public void start() throws Exception {

        // 加载解析server.xml
        loadServer();

        //根据appBase加载项目中的class和web.xml

        loadAppBase();


        ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 50, 100L,
                TimeUnit.SECONDS, new ArrayBlockingQueue<>(50),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        ServerSocket server = new ServerSocket(port);
        System.out.println("====>>minicat start  on  port:" + port);
        while (true) {
            Socket socket = server.accept();
            RequestProcessor requestProcessor = new RequestProcessor(socket, mapper);
            executor.execute(requestProcessor);
        }


    }

    private void loadAppBase() throws FileNotFoundException, ClassNotFoundException {
        Mapper.MappedHost mappedHost = mapper.getMappedHosts().get(0);
        List<Mapper.MappedContext> mappedContexts = new ArrayList<Mapper.MappedContext>();
        String appBase = mappedHost.getAppBase();
        File file = new File(appBase);
        File[] files = file.listFiles();
        for (File file1 : files) {
            Mapper.MappedContext mappedContext = mapper.new MappedContext();
            List<Mapper.MappedWrapper> mappedWrappers = new ArrayList<Mapper.MappedWrapper>();
            String path = file1.getPath();
            mappedContext.setApp(path.substring(path.lastIndexOf("/", path.length())));
            mappedContext.setMappedWrappers(mappedWrappers);
            loadXmlConfig(file1.getAbsolutePath(), mappedContext);
            mappedContexts.add(mappedContext);
        }
        mappedHost.setMappedContexts(mappedContexts);
    }


    private void loadXmlConfig(String absolutePath, Mapper.MappedContext mappedContext) throws FileNotFoundException, ClassNotFoundException {
        File files = new File(absolutePath);
        if (files.isDirectory()) {
            File[] fileArray = files.listFiles();
            for (File file : fileArray) {
                loadXmlConfig(file.getAbsolutePath(), mappedContext);
            }
        }


        String name = files.getName();
        if (name.equalsIgnoreCase("web.xml")) {
            List<Mapper.MappedWrapper> mappedWrappers = mappedContext.getMappedWrappers();
            // 加载解析相关的配置，web.xml
            loadServlet(absolutePath, mappedWrappers);
            mappedContext.setMappedWrappers(mappedWrappers);
        }
    }


    private void loadServer() {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        ArrayList<Mapper.MappedHost> arrayLists = new ArrayList<Mapper.MappedHost>();
        Mapper.MappedHost mappedHost = mapper.new MappedHost();
        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();

            //获取监听端口
            List<Element> connectors = rootElement.selectNodes("//Connector");
            Element connector = connectors.get(0);
            Attribute port = connector.attribute("port");
            this.port = Integer.parseInt(port.getValue());


            //获取监听端口
            List<Element> hosts = rootElement.selectNodes("//Host");
            Element host = hosts.get(0);
            Attribute name = host.attribute("name");
            Attribute appBase = host.attribute("appBase");
            mappedHost.setHost(name.getValue());
            mappedHost.setAppBase(appBase.getValue());


        } catch (DocumentException e) {
            e.printStackTrace();
        }
        arrayLists.add(mappedHost);
        mapper.setMappedHosts(arrayLists);
    }


    /**
     * 加载解析web.xml，初始化Servlet
     */
    private void loadServlet(String absolutePath, List<Mapper.MappedWrapper> mappedWrappers) throws FileNotFoundException, ClassNotFoundException {

        File file = new File(absolutePath);
        InputStream resourceAsStream = new FileInputStream(file);
        SAXReader saxReader = new SAXReader();

        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();

            List<Element> selectNodes = rootElement.selectNodes("//servlet");
            for (int i = 0; i < selectNodes.size(); i++) {
                Element element = selectNodes.get(i);
                // <servlet-name>lagou</servlet-name>
                Element servletnameElement = (Element) element.selectSingleNode("servlet-name");
                String servletName = servletnameElement.getStringValue();
                // <servlet-class>server.LagouServlet</servlet-class>
                Element servletclassElement = (Element) element.selectSingleNode("servlet-class");
                String servletClass = servletclassElement.getStringValue();


                // 根据servlet-name的值找到url-pattern
                Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']");
                // /lagou
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                Mapper.MappedWrapper mappedWrapper = mapper.new MappedWrapper();
                mappedWrapper.setServletClass(servletClass);
                mappedWrapper.setUrlPattern(urlPattern);
                //根据xml路径加载对应class类
                String servletUrl = absolutePath.replaceAll("web.xml", "") + servletClass.replaceAll("\\.", "/") + ".class";
                MyClassLoader myClassLoader = new MyClassLoader(servletUrl);
                Class<?> aClass = myClassLoader.findClass(servletClass);
                HttpServlet httpServlet = (HttpServlet) aClass.newInstance();
                System.out.println(httpServlet);
                mappedWrapper.setHttpServlet(httpServlet);
                mappedWrappers.add(mappedWrapper);
            }


        } catch (DocumentException | InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }

    }


    /**
     * Minicat 的程序启动入口
     *
     * @param args
     */
    public static void main(String[] args) {
        Bootstrap bootstrap = new Bootstrap();
        try {
            // 启动Minicat
            bootstrap.start();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
